﻿using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using MahApps.Metro;
using Red.Controls.Shell;
using Red.Controls.Utils;
using Red.Core;

namespace Red.Launcher
{
    public class MenuData
    {
        #region Public Properties

        public string Name { get; set; }
        public Brush BorderColorBrush { get; set; }
        public Brush ColorBrush { get; set; }

        #endregion Public Properties
    }

    public partial class SettingsView : UserControl, INotifyPropertyChanged
    {
        #region Private Types

        public class SettingsStrings
        {
            public class SettingString
            {
                public string Key { get; set; }
                public string Header { get; set; }
                public string Description { get; set; }
            }

            private IStringProvider<SettingString> _stringProvider = new XmlStringProvider<SettingString>( "settings.strings", "Setting" );

            public SettingString Theme => _stringProvider.GetValue( "theme" );
            public SettingString Accent => _stringProvider.GetValue( "accent" );
            public SettingString DisplayRecentFilesByDefault => _stringProvider.GetValue( "displayRecentFilesByDefault" );
            public SettingString AddRuntimeToEnvironmentalVariables => _stringProvider.GetValue( "addRuntimeToEnvironmentalVariables" );
            public SettingString PersistEnvironmentalVariablesAfterShutdown => _stringProvider.GetValue( "persistEnvironmentalVariablesAfterShutdown" );
            public SettingString PerforceServer => _stringProvider.GetValue( "p4server" );
            public SettingString PerforcePort => _stringProvider.GetValue( "p4port" );
            public SettingString EditorDirectory => _stringProvider.GetValue( "editordir" );
            public SettingString ToolkitDirectory => _stringProvider.GetValue( "toolkitdir" );
            public SettingString EngineDirectory => _stringProvider.GetValue( "enginedir" );
            public SettingString PerforceDirectory => _stringProvider.GetValue( "p4workspacesdir" );
            public SettingString DatabaseServer => _stringProvider.GetValue( "dbserver" );
            public SettingString DatabaseName => _stringProvider.GetValue( "dbname" );
            public SettingString AboutChangelist => _stringProvider.GetValue( "aboutcl" );
            public SettingString AboutBuildId => _stringProvider.GetValue( "aboutbid" );
            public SettingString AboutVersion => _stringProvider.GetValue( "aboutver" );
        }

        #endregion Private Types

        #region Private Data

        private string _theme;
        private string _accent;

        private List<string> _monitoredProperties = new List<string>();

        #endregion Private Data

        #region Public Properties

        public List<MenuData> Accents { get; set; }
        public List<MenuData> Themes { get; set; }

        public MenuData AccentColor
        {
            get { return Accents.Find( item => item.Name == _accent ); }
            set
            {
                if ( _accent != value.Name )
                {
                    _accent = value.Name;
                    AccentChanged?.Invoke( _accent );
                }

                // when put inside 'if', controls won't refresh the first time
                OnPropertyChanged();
            }
        }

        public MenuData AppTheme
        {
            get { return Themes.Find( item => item.Name == _theme ); }
            set
            {
                if ( _theme != value.Name )
                {
                    _theme = value.Name;
                    ThemeChanged?.Invoke( _theme );
                }

                // when put inside 'if', controls won't refresh the first time
                OnPropertyChanged();
            }
        }

        public string EditorPackagesInstallationDirectory
        {
            get { return Settings.EditorPackagesInstallationDirectory; }
            set { Settings.EditorPackagesInstallationDirectory = value; }
        }

        public string ToolkitPackagesInstallationDirectory
        {
            get { return Settings.ToolkitPackagesInstallationDirectory; }
            set { Settings.ToolkitPackagesInstallationDirectory = value; }
        }

        public string EnginePackagesInstallationDirectory
        {
            get { return Settings.EnginePackagesInstallationDirectory; }
            set { Settings.EnginePackagesInstallationDirectory = value; }
        }

        public string WorkspaceInstallationDirectory
        {
            get { return Settings.WorkspaceInstallationDirectory; }
            set { Settings.WorkspaceInstallationDirectory = value; }
        }

        public bool IsValid
        {
            get
            {
                bool isValid = true;

                isValid &= Helpers.ValidateElement( _server );
                isValid &= Helpers.ValidateElement( _port );
                isValid &= Helpers.ValidateElement( _toolkitInstallDirectory );
                isValid &= Helpers.ValidateElement( _engineInstallDirectory );
                isValid &= Helpers.ValidateElement( _databaseServer );
                isValid &= Helpers.ValidateElement( _databaseName );

                return isValid;
            }
        }

        public SettingsStrings Strings { get; set; } = new SettingsStrings();

        #endregion Public Properties

        #region C-Tor

        partial void InitializeAnalytics();

        public SettingsView()
        {
            DataContext = this;
            SetupThemeControls();
            InitializeComponent();

            ThemeChanged += SettingsView_ThemeChanged;
            AccentChanged += SettingsView_AccentChanged;
            Settings.StaticPropertyChanged += Settings_StaticPropertyChanged;

            _monitoredProperties.Add( "EditorPackagesInstallationDirectory" );
            _monitoredProperties.Add( "ToolkitPackagesInstallationDirectory" );
            _monitoredProperties.Add( "EnginePackagesInstallationDirectory" );
            _monitoredProperties.Add( "WorkspaceInstallationDirectory" );
            _monitoredProperties.Add( "AddRuntimeToEnvironmentalVariables" );
            _monitoredProperties.Add( "PersistEnvironmentalVariablesAfterShutdown" );
        }

        #endregion C-Tor

        #region Private Methods

        private void SetupThemeControls()
        {
            Accents = ThemeManager.Accents.Select( a => new MenuData { Name = a.Name, ColorBrush = a.Resources[ "AccentColorBrush" ] as Brush } ).ToList();
            Themes = ThemeManager.AppThemes.Select( a => new MenuData { Name = a.Name, BorderColorBrush = a.Resources[ "BlackColorBrush" ] as Brush, ColorBrush = a.Resources[ "WhiteColorBrush" ] as Brush } ).ToList();
        }

        #endregion Private Methods

        #region RedMainWindow implementation

        public void WriteToSettings( UserSettings settings )
        {
            settings.Theme = AppTheme.Name;
            settings.Accent = AccentColor.Name;
        }

        public void LoadFromSettings( UserSettings settings )
        {
            MenuData theme = new MenuData()
            {
                Name = settings.Theme
            };

            AppTheme = theme;

            MenuData accent = new MenuData()
            {
                Name = settings.Accent
            };

            AccentColor = accent;

            // Start analytics after we've loaded settings (This way we don't interpret loading settings as new user action)
            InitializeAnalytics();
        }

        #endregion RedMainWindow implementation

        #region Events

        public event OnThemeChange ThemeChanged;
        public event OnThemeChange AccentChanged;
        public delegate void OnThemeChange( string theme );

        #endregion Events

        #region Event Handlers

        private void SettingsView_AccentChanged( string accent )
        {
            RedApplication app = Application.Current as RedApplication;
            if ( app != null )
            {
                app.ChangeAccentColor( accent );
            }
        }

        private void SettingsView_ThemeChanged( string theme )
        {
            RedApplication app = Application.Current as RedApplication;
            if ( app != null )
            {
                app.ChangeAppTheme( theme );
            }
        }

        private void Settings_StaticPropertyChanged( object sender, PropertyChangedEventArgs e )
        {
            if ( _monitoredProperties.Exists( p => e.PropertyName == p ) )
            {
                OnPropertyChanged( e.PropertyName );
            }
        }

        #endregion Event Handlers

        #region INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged( [CallerMemberName] string propertyName = null )
        {
            PropertyChanged?.Invoke( this, new PropertyChangedEventArgs( propertyName ) );
        }

        #endregion INotifyPropertyChanged
    }

    #region Validation Rules

    public class IsPortNumberValidationRule : ValidationRule
    {
        public override ValidationResult Validate( object value, System.Globalization.CultureInfo cultureInfo )
        {
            string valueStr = (string)value;

            if ( string.IsNullOrEmpty( valueStr ) )
            {
                return new ValidationResult( false, "Field may not be empty" );
            }

            ushort port;
            if ( !ushort.TryParse( valueStr, out port ) )
            {
                return new ValidationResult( false, "Not a valid port number (Must be between 0-65535)" );
            }

            return new ValidationResult( true, null );
        }
    }

    #endregion Validation Rules
}
